| Trees | Indices | Help |
|---|
|
|
1 # -*- coding: utf-8 -*- 2 3 ''' 4 Task Coach - Your friendly task manager 5 Copyright (C) 2004-2013 Task Coach developers <developers@taskcoach.org> 6 Copyright (C) 2008 Rob McMullen <rob.mcmullen@gmail.com> 7 Copyright (C) 2013 Marcus Johansson <marcus1.johansson@gmail.com> 8 9 Task Coach is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Task Coach is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. 21 ''' 22 23 import wx 24 25 from taskcoachlib import patterns, meta, command, help, widgets, persistence, \ 26 thirdparty, render, operating_system # pylint: disable=W0622 27 from taskcoachlib.command import quickAddParser 28 from taskcoachlib.domain import base, task, note, category, attachment, \ 29 effort, date 30 from taskcoachlib.gui import dialog, printer 31 from taskcoachlib.gui.wizard import CSVImportWizard 32 from taskcoachlib.i18n import _ 33 from taskcoachlib.mailer import sendMail 34 from taskcoachlib.thirdparty import desktop, hypertreelist 35 from taskcoachlib.thirdparty.pubsub import pub 36 from taskcoachlib.thirdparty.wxScheduler import wxSCHEDULER_NEXT, \ 37 wxSCHEDULER_PREV, wxSCHEDULER_TODAY 38 from taskcoachlib.tools import anonymize 39 from taskcoachlib.workarounds import ExceptionAsUnicode 40 import base_uicommand 41 import mixin_uicommand 42 import settings_uicommand47 self.iocontroller = kwargs.pop('iocontroller', None) 48 super(IOCommand, self).__init__(*args, **kwargs)4953 self.taskList = kwargs.pop('taskList', None) 54 super(TaskListCommand, self).__init__(*args, **kwargs)5559 self.effortList = kwargs.pop('effortList', None) 60 super(EffortListCommand, self).__init__(*args, **kwargs)6165 self.categories = kwargs.pop('categories', None) 66 super(CategoriesCommand, self).__init__(*args, **kwargs)67 7377 self.attachments = kwargs.pop('attachments', None) 78 super(AttachmentsCommand, self).__init__(*args, **kwargs)79 8587 return super(ViewerCommand, self).__eq__(other) and \ 88 self.viewer.settingsSection() == other.viewer.settingsSection()8910094 super(FileOpen, self).__init__(menuText=_('&Open...\tCtrl+O'), 95 helpText=help.fileOpen, bitmap='fileopen', id=wx.ID_OPEN, 96 *args, **kwargs)97112104 self.__filename = kwargs.pop('filename') 105 index = kwargs.pop('index') 106 super(RecentFileOpen, self).__init__( \ 107 menuText='%d %s' % (index, self.__filename), 108 helpText=_('Open %s') % self.__filename, *args, **kwargs)109122116 super(FileMerge, self).__init__(menuText=_('&Merge...'), 117 helpText=_('Merge tasks from another file with the current file'), 118 bitmap='merge', *args, **kwargs)119133126 super(FileClose, self).__init__(menuText=_('&Close\tCtrl+W'), 127 helpText=help.fileClose, bitmap='close', id=wx.ID_CLOSE, 128 *args, **kwargs)129146137 super(FileSave, self).__init__(menuText=_('&Save\tCtrl+S'), 138 helpText=help.fileSave, bitmap='save', id=wx.ID_SAVE, 139 *args, **kwargs)140 143159150 super(FileMergeDiskChanges, self).__init__(menuText=_('Merge &disk changes\tShift-Ctrl-M'), 151 helpText=help.fileMergeDiskChanges, bitmap='mergedisk', 152 *args, **kwargs)153 156170163 super(FileSaveAs, self).__init__( \ 164 menuText=_('S&ave as...\tShift+Ctrl+S'), 165 helpText=help.fileSaveAs, bitmap='saveas', id=wx.ID_SAVEAS, 166 *args, **kwargs)167171 172 -class FileSaveSelection(mixin_uicommand.NeedsSelectedTasksMixin, IOCommand, 173 ViewerCommand):182175 super(FileSaveSelection, self).__init__( \ 176 menuText=_('Sa&ve selected tasks to new taskfile...'), 177 helpText=_('Save the selected tasks to a separate taskfile'), 178 bitmap='saveselection', *args, **kwargs)179183 184 -class FileSaveSelectedTaskAsTemplate(mixin_uicommand.NeedsOneSelectedTaskMixin, 185 IOCommand, ViewerCommand):194187 super(FileSaveSelectedTaskAsTemplate, self).__init__( \ 188 menuText=_('Save selected task as &template'), 189 helpText=_('Save the selected task as a task template'), 190 bitmap='saveselection', *args, **kwargs)191205198 super(FileImportTemplate, self).__init__( \ 199 menuText=_('&Import template...'), 200 helpText=_('Import a new template from a template file'), 201 bitmap='fileopen', *args, **kwargs)202218210 super(FileEditTemplates, self).__init__( \ 211 menuText=_('Edit templates...'), 212 helpText=_('Edit existing templates'), *args, **kwargs)213215 templateDialog = dialog.templates.TemplatesDialog(self.settings, 216 self.mainWindow(), title=_('Edit templates')) 217 templateDialog.Show()238222 super(FilePurgeDeletedItems, self).__init__( \ 223 menuText=_('&Purge deleted items'), 224 helpText=_('Actually delete deleted tasks and notes ' 225 '(see the SyncML chapter in Help)'), 226 bitmap='delete', *args, **kwargs)227229 if (wx.MessageBox(_('''Purging deleted items is undoable. 230 If you're planning on enabling 231 the SyncML feature again with the 232 same server you used previously, 233 these items will probably come back. 234 235 Do you still want to purge?'''), 236 _('Warning'), wx.YES_NO) == wx.YES): 237 self.iocontroller.purgeDeletedItems()242 ''' Action for changing page settings. The page settings are saved in the 243 application wide settings. ''' 244260246 super(PrintPageSetup, self).__init__( \ 247 menuText=_('&Page setup...\tShift+Ctrl+P'), 248 helpText=help.printPageSetup, bitmap='pagesetup', 249 id=wx.ID_PRINT_SETUP, *args, **kwargs)250252 printerSettings = printer.PrinterSettings(self.settings) 253 pageSetupDialog = wx.PageSetupDialog(self.mainWindow(), 254 printerSettings.pageSetupData) 255 result = pageSetupDialog.ShowModal() 256 if result == wx.ID_OK: 257 pageSetupData = pageSetupDialog.GetPageSetupData() 258 printerSettings.updatePageSetupData(pageSetupData) 259 pageSetupDialog.Destroy()263 ''' Action for previewing a print of the current viewer. ''' 264281266 super(PrintPreview, self).__init__( \ 267 menuText=_('&Print preview...'), 268 helpText=_('Show a preview of what the print will look like'), 269 bitmap='printpreview', id=wx.ID_PREVIEW, *args, **kwargs)270272 printout, printout2 = printer.Printout(self.viewer, self.settings, 273 twoPrintouts=True) 274 printerSettings = printer.PrinterSettings(self.settings) 275 preview = wx.PrintPreview(printout, printout2, 276 printerSettings.printData) 277 previewFrame = wx.PreviewFrame(preview, self.mainWindow(), 278 _('Print preview'), size=(750, 700)) 279 previewFrame.Initialize() 280 previewFrame.Show()284 ''' Action for printing the contents of the current viewer. ''' 285306287 super(Print, self).__init__(menuText=_('&Print...\tCtrl+P'), 288 helpText=help.print_, bitmap='print', id=wx.ID_PRINT, 289 *args, **kwargs)290292 printerSettings = printer.PrinterSettings(self.settings) 293 printDialogData = wx.PrintDialogData(printerSettings.printData) 294 printDialogData.EnableSelection(True) 295 wxPrinter = wx.Printer(printDialogData) 296 if not wxPrinter.PrintDialog(self.mainWindow()): 297 return 298 printout = printer.Printout(self.viewer, self.settings, 299 printSelectionOnly=wxPrinter.PrintDialogData.Selection) 300 # If the user checks the selection radio button, the ToPage property 301 # gets set to 1. Looks like a bug to me. The simple work-around is to 302 # reset the ToPage property to the MaxPage value if necessary: 303 if wxPrinter.PrintDialogData.Selection: 304 wxPrinter.PrintDialogData.ToPage = wxPrinter.PrintDialogData.MaxPage 305 wxPrinter.Print(self.mainWindow(), printout, prompt=False)309 ''' Base class for export actions. ''' 310331312 exportDialog = self.getExportDialogClass()(self.mainWindow(), 313 settings=self.settings) # pylint: disable=E1101 314 if wx.ID_OK == exportDialog.ShowModal(): 315 exportOptions = exportDialog.options() 316 selectedViewer = exportOptions.pop('selectedViewer') 317 # pylint: disable=W0142 318 self.exportFunction()(selectedViewer, **exportOptions) 319 exportDialog.Destroy()320 321 @staticmethod 325334 ''' Action for exporting the contents of a viewer to HTML. ''' 335348337 super(FileExportAsHTML, self).__init__( \ 338 menuText=_('Export as &HTML...'), 339 helpText=_('Export items from a viewer in HTML format'), 340 bitmap='exportashtml', *args, **kwargs)341 342 @staticmethod 345351 ''' Action for exporting the contents of a viewer to CSV. ''' 352365354 super(FileExportAsCSV, self).__init__(menuText=_('Export as &CSV...'), 355 helpText=_('Export items from a viewer in Comma Separated Values ' 356 '(CSV) format'), 357 bitmap='exportascsv', *args, **kwargs)358 359 @staticmethod 362368 ''' Action for exporting the contents of a viewer to iCalendar format. ''' 369392371 super(FileExportAsICalendar, self).__init__( \ 372 menuText=_('Export as &iCalendar...'), 373 helpText=_('Export items from a viewer in iCalendar format'), 374 bitmap='exportasvcal', *args, **kwargs)375 378 382 383 @staticmethod 386 387 @staticmethod389 ''' Return whether the viewer can be exported to iCalendar format. ''' 390 return aViewer.isShowingTasks() or (aViewer.isShowingEffort() and \ 391 not aViewer.isShowingAggregatedEffort())395 ''' Action for exporting the contents of a viewer to Todo.txt format. ''' 396418398 super(FileExportAsTodoTxt, self).__init__( \ 399 menuText=_('Export as &Todo.txt...'), 400 helpText=_('Export items from a viewer in Todo.txt format ' 401 '(see todotxt.com)'), 402 bitmap='exportascsv', *args, **kwargs)403 409 410 @staticmethod 413 414 @staticmethod416 ''' Return whether the viewer can be exported to Todo.txt format. ''' 417 return aViewer.isShowingTasks()421 ''' Action for exporting the contents of a viewer to PDF. ''' 422 ''' author: Erik Ivarsson ''' 423436425 super(FileExportAsPDF, self).__init__( \ 426 menuText=_('Export as &PDF'), 427 helpText=_('Export items from a viewer in PDF format'), 428 bitmap='exportascsv', *args, **kwargs)429 430 @staticmethod 433438 ''' Action for exporting the contents of a viewer to iCalendar format. ''' 439448441 super(FileExportToGoogleTask, self).__init__( \ 442 menuText=_('Export as &Google Task...'), 443 helpText=_('Export items from a viewer to Google Task'), 444 bitmap='exportascsv', *args, **kwargs)445453 ''' Action for importing data from a CSV file into the current task 454 file. ''' 455477457 super(FileImportCSV, self).__init__(menuText=_('&Import CSV...'), 458 helpText=_('Import tasks from a Comma Separated Values (CSV) file'), 459 bitmap='exportascsv', *args, **kwargs)460462 while True: 463 filename = wx.FileSelector(_('Import CSV'), wildcard='*.csv') 464 if filename: 465 if len(file(filename, 'rb').read()) == 0: 466 wx.MessageBox(_('The selected file is empty. ' 467 'Please select a different file.'), 468 _('Import CSV')) 469 continue 470 wizard = CSVImportWizard(filename, None, wx.ID_ANY, 471 _('Import CSV')) 472 if wizard.RunWizard(): 473 self.iocontroller.importCSV(**wizard.GetOptions()) 474 break 475 else: 476 break480 ''' Action for importing data from a Todo.txt file into the current task 481 file. ''' 482493484 super(FileImportTodoTxt, self).__init__( \ 485 menuText=_('&Import Todo.txt...'), 486 helpText=_('Import tasks from a Todo.txt (see todotxt.com) file'), 487 bitmap='exportascsv', *args, **kwargs)488490 filename = wx.FileSelector(_('Import Todo.txt'), wildcard='*.txt') 491 if filename: 492 self.iocontroller.importTodoTxt(filename)535497 super(FileImportFromGoogleTask, self).__init__( \ 498 menuText=_('&Import Google Task...'), 499 helpText=_('Import Tasks from Google Task'), 500 bitmap='exportascsv', *args, **kwargs)501503 tasklist=self.iocontroller.importFromGoogleTasks() 504 for task in tasklist: 505 506 existingTasks = self.mainWindow().viewer.taskFile.tasks() 507 exists = False 508 509 for existingTask in existingTasks: 510 if existingTask.id()==task['id'] or (existingTask.subject() == task['title'] and 511 existingTask.dueDateTime().strftime("%Y-%m-%dT00:00:00.000Z")==task['due']): 512 exists=True 513 break 514 515 if not exists: 516 category = self.mainWindow().taskFile.categories().findCategoryByName(task['Category']) 517 if category is None: 518 newCategoryCommand = command.NewCategoryCommand(self.mainWindow().taskFile.categories(), 519 subject=task['Category']) 520 newCategoryCommand.do() 521 category = self.mainWindow().taskFile.categories().findCategoryByName(task['Category']) 522 523 print task 524 newTaskCommand = command.NewTaskCommand(self.mainWindow().taskFile.tasks(), 525 subject=task['title'] if 'title' in task else '', 526 description=task['notes'] if 'notes' in task else '', 527 dueDateTime=date.DateTime.strptime 528 (task['due'],'%Y-%m-%dT%H:%M:%S.%fz') if 'due' in task 529 else date.DateTime.strptime 530 ('2010-10-15T12:00:00.000Z','%Y-%m-%dT%H:%M:%S.%fz'), 531 percentageComplete=100 if task['status']=='completed' else 0, 532 categories=[category],id=task['id']) 533 534 newTaskCommand.do()550539 super(FileBackupGoogleDrive, self).__init__( \ 540 menuText=_('&Backup to Google Drive'), 541 helpText=_('Backup your Taskfile to Google Drive'), 542 bitmap='', *args, **kwargs)543545 if self.mainWindow().viewer.taskFile.__str__() != "": 546 self.iocontroller.uploadToGoogleDrive(self.mainWindow().viewer.taskFile.__str__()) 547 wx.MessageBox("Backup completed",'Backup completed',wx.OK|wx.ICON_INFORMATION) 548 else: 549 wx.MessageBox('Please save task before doing a backup','Backup error',wx.OK|wx.ICON_ERROR)553 ''' Action for synchronizing the current task file with a SyncML 554 server. ''' 555564557 super(FileSynchronize, self).__init__( \ 558 menuText=_('S&yncML synchronization...'), 559 helpText=_('Synchronize with a SyncML server'), 560 bitmap='arrows_looped_icon', *args, **kwargs)561567 ''' Action for quitting the application. ''' 568576570 super(FileQuit, self).__init__(menuText=_('&Quit\tCtrl+Q'), 571 helpText=help.fileQuit, bitmap='exit', id=wx.ID_EXIT, 572 *args, **kwargs)573579 ''' Action for undoing the previous user action. ''' 580610582 super(EditUndo, self).__init__(menuText=self.getUndoMenuText(), 583 helpText=help.editUndo, bitmap='undo', id=wx.ID_UNDO, 584 *args, **kwargs)585 586 @staticmethod588 ''' Return the menu text for the undo command, including a text 589 describing the previous user action. ''' 590 return '%s\tCtrl+Z' % patterns.CommandHistory().undostr(_('&Undo'))591593 windowWithFocus = wx.Window.FindFocus() 594 if isinstance(windowWithFocus, wx.TextCtrl): 595 windowWithFocus.Undo() 596 else: 597 patterns.CommandHistory().undo()598 602604 windowWithFocus = wx.Window.FindFocus() 605 if isinstance(windowWithFocus, wx.TextCtrl): 606 return windowWithFocus.CanUndo() 607 else: 608 return patterns.CommandHistory().hasHistory() and \ 609 super(EditUndo, self).enabled(event)613 ''' Action for redoing the last undone user action. ''' 614644616 super(EditRedo, self).__init__(menuText=self.getRedoMenuText(), 617 helpText=help.editRedo, bitmap='redo', id=wx.ID_REDO, 618 *args, **kwargs)619 620 @staticmethod622 ''' Return the menu text for the redo command, including a text 623 describing the next user action. ''' 624 return '%s\tCtrl+Y' % patterns.CommandHistory().redostr(_('&Redo'))625627 windowWithFocus = wx.Window.FindFocus() 628 if isinstance(windowWithFocus, wx.TextCtrl): 629 windowWithFocus.Redo() 630 else: 631 patterns.CommandHistory().redo()632 636647 ''' Action for cutting the currently selected item(s) to the 648 clipboard. ''' 649668651 super(EditCut, self).__init__(menuText=_('Cu&t\tCtrl+X'), 652 helpText=help.editCut, bitmap='cut', *args, **kwargs)653655 windowWithFocus = wx.Window.FindFocus() 656 if isinstance(windowWithFocus, wx.TextCtrl): 657 windowWithFocus.Cut() 658 else: 659 cutCommand = self.viewer.cutItemCommand() 660 cutCommand.do()661671 ''' Action for copying the currently selected item(s) to the 672 clipboard. ''' 673693675 super(EditCopy, self).__init__(menuText=_('&Copy\tCtrl+C'), 676 helpText=help.editCopy, bitmap='copy', *args, **kwargs)677679 windowWithFocus = wx.Window.FindFocus() 680 if isinstance(windowWithFocus, wx.TextCtrl): 681 windowWithFocus.Copy() 682 else: 683 copyCommand = command.CopyCommand(self.viewer.presentation(), 684 self.viewer.curselection()) 685 copyCommand.do()686696 ''' Action for pasting the item(s) in the clipboard into the current 697 taskfile. ''' 698718700 super(EditPaste, self).__init__(menuText=_('&Paste\tCtrl+V'), 701 helpText=help.editPaste, bitmap='paste', id=wx.ID_PASTE, 702 *args, **kwargs)703705 windowWithFocus = wx.Window.FindFocus() 706 if isinstance(windowWithFocus, wx.TextCtrl): 707 windowWithFocus.Paste() 708 else: 709 pasteCommand = command.PasteCommand() 710 pasteCommand.do()711722 ''' Action for pasting the item(s) in the clipboard into the current 723 taskfile, as a subitem of the currently selected item. ''' 724760726 super(EditPasteAsSubItem, self).__init__( 727 menuText=_('P&aste as subitem\tShift+Ctrl+V'), 728 helpText=help.editPasteAsSubitem, bitmap='pasteintotask', 729 *args, **kwargs)730732 pasteCommand = command.PasteAsSubItemCommand( 733 items=self.viewer.curselection()) 734 pasteCommand.do()735737 if not (super(EditPasteAsSubItem, self).enabled(event) and \ 738 command.Clipboard()): 739 return False 740 targetClass = self.viewer.curselection()[0].__class__ 741 pastedClasses = [item.__class__ for item in command.Clipboard().peek()] 742 return self.__targetAndPastedAreEqual(targetClass, pastedClasses) or \ 743 self.__targetIsTaskAndPastedIsEffort(targetClass, pastedClasses)744 745 @classmethod747 ''' Return whether the target class is a task and the pasted classes 748 are all effort. ''' 749 if targetClass != task.Task: 750 return False 751 return cls.__targetAndPastedAreEqual(effort.Effort, pastedClasses)752 753 @staticmethod763 ''' Action for bringing up the preferences dialog. ''' 764775766 super(EditPreferences, self).__init__( \ 767 menuText=_('&Preferences...\tAlt+P'), 768 helpText=help.editPreferences, bitmap='wrench_icon', 769 id=wx.ID_PREFERENCES, *args, **kwargs)770 772 editor = dialog.preferences.Preferences(parent=self.mainWindow(), 773 title=_('Preferences'), settings=self.settings) 774 editor.Show(show=show)778 ''' Action for bringing up the synchronization preferences dialog. ''' 779791781 super(EditSyncPreferences, self).__init__( \ 782 menuText=_('&SyncML preferences...'), 783 helpText=_('Edit SyncML preferences'), bitmap='arrows_looped_icon', 784 *args, **kwargs)785 787 editor = dialog.syncpreferences.SyncMLPreferences( \ 788 parent=self.mainWindow(), iocontroller=self.iocontroller, 789 title=_('SyncML preferences')) 790 editor.Show(show=show)794 ''' Action for editing a customizable toolbar ''' 795806797 self.__toolbar = toolbar 798 self.__editorClass = editorClass 799 super(EditToolBarPerspective, self).__init__( \ 800 helpText=_('Customize toolbar'), bitmap='cogwheel_icon', 801 menuText=_('Customize'), 802 *args, **kwargs)803805 self.__editorClass(self.__toolbar, self.settings, self.mainWindow(), _('Customize toolbar')).ShowModal()809 ''' Action for selecting all items in a viewer. ''' 810828812 super(SelectAll, self).__init__(menuText=_('&All\tCtrl+A'), 813 helpText=help.editSelectAll, bitmap='selectall', 814 id=wx.ID_SELECTALL, *args, **kwargs)815817 windowWithFocus = wx.Window.FindFocus() 818 if self.windowIsTextCtrl(windowWithFocus): 819 windowWithFocus.SetSelection(-1, -1) # Select all text 820 else: 821 self.viewer.select_all()822 823 @staticmethod825 ''' Return whether the window is a text control. ''' 826 return isinstance(window, wx.TextCtrl) or \ 827 isinstance(window, hypertreelist.EditCtrl)831 ''' Action for unselecting all items in a viewer. ''' 832839834 super(ClearSelection, self).__init__(menuText=_('&Clear selection'), 835 helpText=_('Unselect all items'), *args, **kwargs)836842 ''' Action for resetting all filters so that all items in all viewers 843 become visible. ''' 844855846 super(ResetFilter, self).__init__( \ 847 menuText=_('&Clear all filters\tShift-Ctrl-R'), 848 helpText=help.resetFilter, bitmap='viewalltasks', *args, **kwargs)849 852856 857 -class ResetCategoryFilter(mixin_uicommand.NeedsAtLeastOneCategoryMixin, 858 CategoriesCommand):859 ''' Action for resetting all category filters so that items are no longer 860 hidden if the don't belong to a certain category. ''' 861869863 super(ResetCategoryFilter, self).__init__( \ 864 menuText=_('&Reset all categories\tCtrl-R'), 865 helpText=help.resetCategoryFilter, *args, **kwargs)866872 ''' Action for toggling filtering on a specific category. ''' 873894875 self.category = kwargs.pop('category') 876 subject = self.category.subject() 877 # Would like to use wx.ITEM_RADIO for mutually exclusive categories, but 878 # a menu with radio items always has to have at least of the items 879 # checked, while we allow none of the mutually exclusive categories to 880 # be checked. Dynamically changing between wx.ITEM_CHECK and 881 # wx.ITEM_RADIO would be a work-around in theory, using wx.ITEM_CHECK 882 # when none of the mutually exclusive categories is checked and 883 # wx.ITEM_RADIO otherwise, but dynamically changing the type of menu 884 # items isn't possible. Hence, we use wx.ITEM_CHECK, even for mutual 885 # exclusive categories. 886 kind = wx.ITEM_CHECK 887 super(ToggleCategoryFilter, self).__init__( \ 888 menuText='&' + subject.replace('&', '&&'), 889 helpText=_('Show/hide items belonging to %s') % subject, kind=kind, 890 *args, **kwargs)891897 ''' Action for opening a new viewer of a specific class. ''' 898918900 self.taskFile = kwargs.pop('taskFile') 901 self.viewerClass = kwargs.pop('viewerClass') 902 kwargs.setdefault('bitmap', self.viewerClass.defaultBitmap) 903 super(ViewViewer, self).__init__(*args, **kwargs)904906 from taskcoachlib.gui import viewer 907 908 viewer.addOneViewer(self.viewer, self.taskFile, self.settings, 909 self.viewerClass) 910 self.increaseViewerCount()911913 ''' Increase the viewer count for the viewer class this command is 914 opening and store the viewer count in the settings. ''' 915 setting = self.viewerClass.__name__.lower() + 'count' 916 viewerCount = self.settings.getint('view', setting) 917 self.settings.set('view', setting, str(viewerCount + 1))919 920 -class ViewEffortViewerForSelectedTask(mixin_uicommand.NeedsOneSelectedTaskMixin, 921 settings_uicommand.SettingsCommand, 922 ViewerCommand):937924 from taskcoachlib.gui import viewer 925 926 self.viewerClass = viewer.EffortViewer 927 self.taskFile = kwargs.pop('taskFile') 928 kwargs['bitmap'] = viewer.EffortViewer.defaultBitmap 929 super(ViewEffortViewerForSelectedTask, self).__init__(*args, **kwargs)930932 from taskcoachlib.gui import viewer 933 934 viewer.addOneViewer(self.viewer, self.taskFile, self.settings, 935 self.viewerClass, 936 tasksToShowEffortFor=task.TaskList(self.viewer.curselection()))955941 super(RenameViewer, self).__init__(menuText=_('&Rename viewer...'), 942 helpText=_('Rename the selected viewer'), *args, **kwargs)943945 activeViewer = self.viewer.activeViewer() 946 viewerNameDialog = wx.TextEntryDialog(self.mainWindow(), 947 _('New title for the viewer:'), _('Rename viewer'), 948 activeViewer.title()) 949 if viewerNameDialog.ShowModal() == wx.ID_OK: 950 activeViewer.setTitle(viewerNameDialog.GetValue()) 951 viewerNameDialog.Destroy()952967959 self.direction = kwargs.pop('forward') 960 super(ActivateViewer, self).__init__(*args, **kwargs)961 964991 1000971 super(HideCurrentColumn, self).__init__(menuText=_('&Hide this column'), 972 helpText=_('Hide the selected column'), *args, **kwargs)973975 columnPopupMenu = event.GetEventObject() 976 self.viewer.hideColumn(columnPopupMenu.columnIndex)977979 # Unfortunately the event (an UpdateUIEvent) does not give us any 980 # information to determine the current column, so we have to find 981 # the column ourselves. We use the current mouse position to do so. 982 widget = self.viewer.getWidget() # Must use method to make sure viewer dispatch works! 983 x, y = widget.ScreenToClient(wx.GetMousePosition()) 984 # Use wx.Point because CustomTreeCtrl assumes a wx.Point instance: 985 columnIndex = widget.HitTest(wx.Point(x, y))[2] 986 # The TreeListCtrl returns -1 for the first column sometimes, 987 # don't understand why. Work around as follows: 988 if columnIndex == -1: 989 columnIndex = 0 990 return self.viewer.isHideableColumn(columnIndex)10131004 for columnName in self.setting: 1005 if not self.viewer.isVisibleColumnByName(columnName): 1006 return False 1007 return True10081010 show = self._isMenuItemChecked(event) 1011 for columnName in self.setting: 1012 self.viewer.showColumnByName(columnName, show)10271017 super(ViewExpandAll, self).__init__( \ 1018 menuText=_('&Expand all items\tShift+Ctrl+E'), 1019 helpText=help.viewExpandAll, *args, **kwargs)1020 10241041 10491031 super(ViewCollapseAll, self).__init__( \ 1032 menuText=_('&Collapse all items\tShift+Ctrl+C'), 1033 helpText=help.viewCollapseAll, *args, **kwargs)10341036 return super(ViewCollapseAll, self).enabled(event) and \ 1037 self.viewer.isAnyItemCollapsable()103810621053 super(ViewerSortOrderCommand, self).__init__(menuText=_('&Ascending'), 1054 helpText=_('Sort ascending (checked) or descending (unchecked)'), 1055 *args, **kwargs)1056 105910771066 super(ViewerSortCaseSensitive, self).__init__( \ 1067 menuText=_('Sort &case sensitive'), 1068 helpText=_('When comparing text, sorting is case sensitive ' 1069 '(checked) or insensitive (unchecked)'), 1070 *args, **kwargs)1071 10741078 1079 -class ViewerSortByTaskStatusFirst(ViewerCommand, 1080 settings_uicommand.UICheckCommand):10931082 super(ViewerSortByTaskStatusFirst, self).__init__( \ 1083 menuText=_('Sort by status &first'), 1084 helpText=_('Sort tasks by status (active/inactive/completed) ' 1085 'first'), 1086 *args, **kwargs)1087 109011151097 self.__taskStatus = taskStatus 1098 super(ViewerHideTasks, self).__init__(menuText=taskStatus.hideMenuText, 1099 helpText=taskStatus.hideHelpText, 1100 bitmap=taskStatus.getHideBitmap(kwargs['settings']), 1101 *args, **kwargs)1102 1105 11081110 if wx.GetKeyState(wx.WXK_SHIFT): 1111 self.viewer.showOnlyTaskStatus(self.__taskStatus) 1112 else: 1113 self.viewer.hideTaskStatus(self.__taskStatus, 1114 self._isMenuItemChecked(event))11331120 super(ViewerHideCompositeTasks, self).__init__( \ 1121 menuText=_('Hide c&omposite tasks'), 1122 helpText=_('Show/hide tasks with subtasks in list mode'), 1123 *args, **kwargs)1124 1127 113011561137 super(Edit, self).__init__(menuText=_('&Edit...\tRETURN'), 1138 helpText=_('Edit the selected item(s)'), bitmap='edit', 1139 *args, **kwargs)1140 1142 windowWithFocus = wx.Window.FindFocus() 1143 editCtrl = self.findEditCtrl(windowWithFocus) 1144 if editCtrl: 1145 editCtrl.AcceptChanges() 1146 if editCtrl: 1147 editCtrl.Finish() 1148 return 1149 try: 1150 columnName = event.columnName 1151 except AttributeError: 1152 columnName = '' 1153 editor = self.viewer.editItemDialog(self.viewer.curselection(), 1154 self.bitmap, columnName) 1155 editor.Show(show)1158 windowWithFocus = wx.Window.FindFocus() 1159 if self.findEditCtrl(windowWithFocus): 1160 return True 1161 elif operating_system.isMac() and isinstance(windowWithFocus, 1162 wx.TextCtrl): 1163 return False 1164 else: 1165 return super(Edit, self).enabled(event)11661168 while windowWithFocus: 1169 if isinstance(windowWithFocus, thirdparty.hypertreelist.EditCtrl): 1170 break 1171 windowWithFocus = windowWithFocus.GetParent() 1172 return windowWithFocus117311911177 super(EditTrackedTasks, self).__init__( \ 1178 menuText=_('Edit &tracked task...\tShift-Alt-T'), 1179 helpText=_('Edit the currently tracked task(s)'), bitmap='edit', 1180 *args, **kwargs)11811183 editTaskDialog = dialog.editor.TaskEditor(self.mainWindow(), 1184 self.taskList.tasksBeingTracked(), self.settings, self.taskList, 1185 self.mainWindow().taskFile, bitmap=self.bitmap) 1186 editTaskDialog.Show(show) 1187 return editTaskDialog # for testing purposes11881190 return any(self.taskList.tasksBeingTracked())12231195 super(Delete, self).__init__(menuText=_('&Delete\tDEL'), 1196 helpText=_('Delete the selected item(s)'), bitmap='delete', 1197 *args, **kwargs)11981200 windowWithFocus = wx.Window.FindFocus() 1201 if self.windowIsTextCtrl(windowWithFocus): 1202 # Simulate Delete key press 1203 fromIndex, toIndex = windowWithFocus.GetSelection() 1204 if fromIndex == toIndex: 1205 pos = windowWithFocus.GetInsertionPoint() 1206 fromIndex, toIndex = pos, pos + 1 1207 windowWithFocus.Remove(fromIndex, toIndex) 1208 else: 1209 deleteCommand = self.viewer.deleteItemCommand() 1210 deleteCommand.do()12111213 windowWithFocus = wx.Window.FindFocus() 1214 if self.windowIsTextCtrl(windowWithFocus): 1215 return True 1216 else: 1217 return super(Delete, self).enabled(event)1218 1219 @staticmethod1257 1260 1263 12661227 self.taskKeywords = kwargs.pop('taskKeywords', dict()) 1228 taskList = kwargs['taskList'] 1229 if 'menuText' not in kwargs: # Provide for subclassing 1230 kwargs['menuText'] = taskList.newItemMenuText 1231 kwargs['helpText'] = taskList.newItemHelpText 1232 super(TaskNew, self).__init__(bitmap='new', *args, **kwargs)1233 1235 kwargs = self.taskKeywords.copy() 1236 if self.__shouldPresetPlannedStartDateTime(): 1237 kwargs['plannedStartDateTime'] = task.Task.suggestedPlannedStartDateTime() 1238 if self.__shouldPresetDueDateTime(): 1239 kwargs['dueDateTime'] = task.Task.suggestedDueDateTime() 1240 if self.__shouldPresetActualStartDateTime(): 1241 kwargs['actualStartDateTime'] = task.Task.suggestedActualStartDateTime() 1242 if self.__shouldPresetCompletionDateTime(): 1243 kwargs['completionDateTime'] = task.Task.suggestedCompletionDateTime() 1244 if self.__shouldPresetReminderDateTime(): 1245 kwargs['reminder'] = task.Task.suggestedReminderDateTime() 1246 newTaskCommand = command.NewTaskCommand(self.taskList, 1247 categories=self.categoriesForTheNewTask(), 1248 prerequisites=self.prerequisitesForTheNewTask(), 1249 dependencies=self.dependenciesForTheNewTask(), 1250 **kwargs) 1251 newTaskCommand.do() 1252 newTaskDialog = dialog.editor.TaskEditor(self.mainWindow(), 1253 newTaskCommand.items, self.settings, self.taskList, 1254 self.mainWindow().taskFile, bitmap=self.bitmap, items_are_new=True) 1255 newTaskDialog.Show(show) 1256 return newTaskDialog # for testing purposes1268 return 'plannedStartDateTime' not in self.taskKeywords and \ 1269 self.settings.get('view', 'defaultplannedstartdatetime').startswith('preset')12701272 return 'dueDateTime' not in self.taskKeywords and \ 1273 self.settings.get('view', 'defaultduedatetime').startswith('preset')12741276 return 'actualStartDateTime' not in self.taskKeywords and \ 1277 self.settings.get('view', 'defaultactualstartdatetime').startswith('preset')12781280 return 'completionDateTime' not in self.taskKeywords and \ 1281 self.settings.get('view', 'defaultcompletiondatetime').startswith('preset')12821284 return 'reminder' not in self.taskKeywords and \ 1285 self.settings.get('view', 'defaultreminderdatetime').startswith('preset')128613141290 super(TaskNewFromTemplate, self).__init__(*args, **kwargs) 1291 self.__filename = filename 1292 templateTask = self.__readTemplate() 1293 self.menuText = '&' + templateTask.subject().replace('&', '&&') # pylint: disable=E11031294 1298 1300 # The task template is read every time because it's the 1301 # TemplateXMLReader that evaluates dynamic values (Now() 1302 # should be evaluated at task creation for instance). 1303 templateTask = self.__readTemplate() 1304 kwargs = templateTask.__getcopystate__() # pylint: disable=E1103 1305 kwargs['categories'] = self.categoriesForTheNewTask() 1306 newTaskCommand = command.NewTaskCommand(self.taskList, **kwargs) 1307 newTaskCommand.do() 1308 # pylint: disable=W0142 1309 newTaskDialog = dialog.editor.TaskEditor(self.mainWindow(), 1310 newTaskCommand.items, self.settings, self.taskList, 1311 self.mainWindow().taskFile, bitmap=self.bitmap, items_are_new=True) 1312 newTaskDialog.Show(show) 1313 return newTaskDialog # for testing purposes1315 1316 -class TaskNewFromTemplateButton(mixin_uicommand.PopupButtonMixin, 1317 TaskListCommand, 1318 settings_uicommand.SettingsCommand):13301320 from taskcoachlib.gui import menu 1321 1322 return menu.TaskTemplateMenu(self.mainWindow(), self.taskList, 1323 self.settings)13241326 return _('New from &template')13271329 return _('Create a new task from a template')13411334 super(NewTaskWithSelectedCategories, self).__init__( \ 1335 menuText=_('New task with selected &categories...'), 1336 helpText=_('Insert a new task with the selected categories checked'), 1337 *args, **kwargs)13381342 1343 -class NewTaskWithSelectedTasksAsPrerequisites( \ 1344 mixin_uicommand.NeedsSelectedTasksMixin, TaskNew, ViewerCommand):13531346 super(NewTaskWithSelectedTasksAsPrerequisites, self).__init__( 1347 menuText=_('New task with selected tasks as &prerequisites...'), 1348 helpText=_('Insert a new task with the selected tasks as prerequisite tasks'), 1349 *args, **kwargs)13501354 1355 -class NewTaskWithSelectedTasksAsDependencies( \ 1356 mixin_uicommand.NeedsSelectedTasksMixin, TaskNew, ViewerCommand):13651358 super(NewTaskWithSelectedTasksAsDependencies, self).__init__( 1359 menuText=_('New task with selected tasks as &dependents...'), 1360 helpText=_('Insert a new task with the selected tasks as dependent tasks'), 1361 *args, **kwargs)13621366 1367 -class NewSubItem(mixin_uicommand.NeedsOneSelectedCompositeItemMixin, 1368 ViewerCommand):1369 shortcut = ('\tCtrl+INS' if operating_system.isWindows() else '\tShift+Ctrl+N') 1370 defaultMenuText = _('New &subitem...') + shortcut 1371 labels = {task.Task: _('New &subtask...'), 1372 note.Note: _('New &subnote...'), 1373 category.Category: _('New &subcategory...')} 13741382 1386 13921376 super(NewSubItem, self).__init__(menuText=self.defaultMenuText, 1377 helpText=_('Insert a new subitem of the selected item'), 1378 bitmap='newsub', *args, **kwargs)1379 1381 self.viewer.newSubItemDialog(bitmap=self.bitmap).Show(show)1393 1394 -class TaskMarkActive(mixin_uicommand.NeedsSelectedTasksMixin, settings_uicommand.SettingsCommand, ViewerCommand):14111396 super(TaskMarkActive, self).__init__(bitmap=task.active.getBitmap(kwargs['settings']), 1397 menuText=_('Mark task &active\tAlt+RETURN'), 1398 helpText=_('Mark the selected task(s) active'), 1399 *args, **kwargs)1400 14041406 def canBeMarkedActive(aTask): 1407 return aTask.actualStartDateTime() > date.Now() or aTask.completed()1408 1409 return super(TaskMarkActive, self).enabled(event) and \ 1410 any([canBeMarkedActive(task) for task in self.viewer.curselection()])1412 1413 -class TaskMarkInactive(mixin_uicommand.NeedsSelectedTasksMixin, settings_uicommand.SettingsCommand, ViewerCommand):14301415 super(TaskMarkInactive, self).__init__(bitmap=task.inactive.getBitmap(kwargs['settings']), 1416 menuText=_('Mark task &inactive\tCtrl+Alt+RETURN'), 1417 helpText=_('Mark the selected task(s) inactive'), 1418 *args, **kwargs)1419 1423 1427 1428 return super(TaskMarkInactive, self).enabled(event) and \ 1429 any([canBeMarkedInactive(task) for task in self.viewer.curselection()])1431 1432 -class TaskMarkCompleted(mixin_uicommand.NeedsSelectedTasksMixin, settings_uicommand.SettingsCommand, ViewerCommand):14501434 super(TaskMarkCompleted, self).__init__(bitmap=task.completed.getBitmap(kwargs['settings']), 1435 menuText=_('Mark task &completed\tCtrl+RETURN'), 1436 helpText=_('Mark the selected task(s) completed'), 1437 *args, **kwargs)14381440 markCompletedCommand = command.MarkCompletedCommand( \ 1441 self.viewer.presentation(), self.viewer.curselection()) 1442 markCompletedCommand.do()1443 1447 1448 return super(TaskMarkCompleted, self).enabled(event) and \ 1449 any([canBeMarkedCompleted(task) for task in self.viewer.curselection()])1451 1452 -class TaskMaxPriority(mixin_uicommand.NeedsSelectedTasksMixin, TaskListCommand, 1453 ViewerCommand):14641455 super(TaskMaxPriority, self).__init__( 1456 menuText=_('&Maximize priority\tShift+Ctrl+I'), 1457 helpText=help.taskMaxPriority, bitmap='maxpriority', 1458 *args, **kwargs)14591461 maxPriority = command.MaxPriorityCommand(self.taskList, 1462 self.viewer.curselection()) 1463 maxPriority.do()1465 1466 -class TaskMinPriority(mixin_uicommand.NeedsSelectedTasksMixin, TaskListCommand, 1467 ViewerCommand):14781469 super(TaskMinPriority, self).__init__( 1470 menuText=_('&Minimize priority\tShift+Ctrl+D'), 1471 helpText=help.taskMinPriority, bitmap='minpriority', 1472 *args, **kwargs)14731475 minPriority = command.MinPriorityCommand(self.taskList, 1476 self.viewer.curselection()) 1477 minPriority.do()1479 1480 -class TaskIncPriority(mixin_uicommand.NeedsSelectedTasksMixin, TaskListCommand, 1481 ViewerCommand):14921483 super(TaskIncPriority, self).__init__( 1484 menuText=_('&Increase priority\tCtrl+I'), 1485 helpText=help.taskIncreasePriority, bitmap='incpriority', 1486 *args, **kwargs)14871489 incPriority = command.IncPriorityCommand(self.taskList, 1490 self.viewer.curselection()) 1491 incPriority.do()1493 1494 -class TaskDecPriority(mixin_uicommand.NeedsSelectedTasksMixin, TaskListCommand, 1495 ViewerCommand):15061497 super(TaskDecPriority, self).__init__( 1498 menuText=_('&Decrease priority\tCtrl+D'), 1499 helpText=help.taskDecreasePriority, bitmap='decpriority', 1500 *args, **kwargs)15011503 decPriority = command.DecPriorityCommand(self.taskList, 1504 self.viewer.curselection()) 1505 decPriority.do()1510 ''' Override onCommandActivate to be able to accept two items instead 1511 of one event. ''' 1512 self.doCommand(dropItem, dragItems, part)1513 1515 dragAndDropCommand = self.createCommand(dropItem=dropItem, dragItems=dragItems, part=part) 1516 if dragAndDropCommand.canDo(): 1517 dragAndDropCommand.do() 1518 152115271525 return command.DragAndDropTaskCommand(self.taskList, dragItems, 1526 drop=[dropItem], part=part)1528 1529 -class ToggleCategory(mixin_uicommand.NeedsSelectedCategorizableMixin, 1530 ViewerCommand):15751532 self.category = kwargs.pop('category') 1533 subject = self.category.subject() 1534 # Would like to use wx.ITEM_RADIO for mutually exclusive categories, but 1535 # a menu with radio items always has to have at least of the items 1536 # checked, while we allow none of the mutually exclusive categories to 1537 # be checked. Dynamically changing between wx.ITEM_CHECK and 1538 # wx.ITEM_RADIO would be a work-around in theory, using wx.ITEM_CHECK 1539 # when none of the mutually exclusive categories is checked and 1540 # wx.ITEM_RADIO otherwise, but dynamically changing the type of menu 1541 # items isn't possible. Hence, we use wx.ITEM_CHECK, even for mutual 1542 # exclusive categories. 1543 kind = wx.ITEM_CHECK 1544 super(ToggleCategory, self).__init__(menuText='&' + subject.replace('&', '&&'), 1545 helpText=_('Toggle %s') % subject, kind=kind, *args, **kwargs)15461548 check = command.ToggleCategoryCommand(category=self.category, 1549 items=self.viewer.curselection()) 1550 check.do()15511553 super(ToggleCategory, self).onUpdateUI(event) 1554 if self.enabled(event): 1555 check = self.__all_selected_items_are_in_category() 1556 for menuItem in self.menuItems: 1557 menuItem.Check(check)15581560 selected_items_in_category = [item for item in self.viewer.curselection() \ 1561 if self.category in item.categories()] 1562 return selected_items_in_category == self.viewer.curselection()15631565 viewerHasSelection = super(ToggleCategory, self).enabled(event) 1566 if not viewerHasSelection or self.viewer.isShowingCategories(): 1567 return False 1568 mutual_exclusive_ancestors = [ancestor for ancestor in self.category.ancestors() \ 1569 if ancestor.isMutualExclusive()] 1570 for categorizable in self.viewer.curselection(): 1571 for ancestor in mutual_exclusive_ancestors: 1572 if ancestor not in categorizable.categories(): 1573 return False # Not all mutually exclusive ancestors are checked 1574 return True # All mutually exclusive ancestors are checked15881579 menuText = _('&Mail...\tShift-Ctrl-M') if operating_system.isMac() else _('&Mail...\tCtrl-M') 1580 super(Mail, self).__init__(menuText=menuText, 1581 helpText=help.mailItem, bitmap='envelope_icon', *args, **kwargs)1582 1584 items = self.viewer.curselection() 1585 subject = self.subject(items) 1586 body = self.body(items) 1587 self.mail(subject, body, mail, showerror)1590 assert items 1591 if len(items) > 2: 1592 return _('Several things') 1593 elif len(items) == 2: 1594 subjects = [item.subject(recursive=True) for item in items] 1595 return ' '.join([subjects[0], _('and'), subjects[1]]) 1596 else: 1597 return items[0].subject(recursive=True)15981600 if len(items) > 1: 1601 bodyLines = [] 1602 for item in items: 1603 bodyLines.extend(self.itemToLines(item)) 1604 else: 1605 bodyLines = items[0].description().splitlines() 1606 return '\r\n'.join(bodyLines)16071609 lines = [] 1610 subject = item.subject(recursive=True) 1611 lines.append(subject) 1612 if item.description(): 1613 lines.extend(item.description().splitlines()) 1614 lines.extend('\r\n') 1615 return lines16161618 try: 1619 mail('', subject, body) 1620 except: 1621 # Try again with a dummy recipient: 1622 try: 1623 mail('recipient@domain.com', subject, body) 1624 except Exception, reason: # pylint: disable=W0703 1625 showerror(_('Cannot send email:\n%s') % ExceptionAsUnicode(reason), 1626 caption=_('%s mail error') % meta.name, 1627 style=wx.ICON_ERROR)16281629 1630 -class AddNote(mixin_uicommand.NeedsSelectedNoteOwnersMixin, ViewerCommand, 1631 settings_uicommand.SettingsCommand):16451633 super(AddNote, self).__init__(menuText=_('Add ¬e...\tCtrl+B'), 1634 helpText=help.addNote, bitmap='new', *args, **kwargs)1635 1637 addNoteCommand = command.AddNoteCommand(self.viewer.presentation(), 1638 self.viewer.curselection()) 1639 addNoteCommand.do() 1640 editDialog = dialog.editor.NoteEditor(self.mainWindow(), 1641 addNoteCommand.items, self.settings, self.viewer.presentation(), 1642 self.mainWindow().taskFile, bitmap=self.bitmap) 1643 editDialog.Show(show) 1644 return editDialog # for testing purposes1646 1647 -class OpenAllNotes(mixin_uicommand.NeedsSelectedNoteOwnersMixinWithNotes, 1648 ViewerCommand, settings_uicommand.SettingsCommand):16601650 super(OpenAllNotes, self).__init__(menuText=_('Open all notes...\tShift+Ctrl+B'), 1651 helpText=help.openAllNotes, bitmap='edit', *args, **kwargs)16521654 for item in self.viewer.curselection(): 1655 for note in item.notes(): 1656 editDialog = dialog.editor.NoteEditor(self.mainWindow(), 1657 [note], self.settings, self.viewer.presentation(), 1658 self.mainWindow().taskFile, bitmap=self.bitmap) 1659 editDialog.Show()1661 1662 -class EffortNew(mixin_uicommand.NeedsAtLeastOneTaskMixin, ViewerCommand, 1663 EffortListCommand, TaskListCommand, 1664 settings_uicommand.SettingsCommand):16981666 effortList = kwargs['effortList'] 1667 super(EffortNew, self).__init__(bitmap='new', 1668 menuText=effortList.newItemMenuText, 1669 helpText=effortList.newItemHelpText, *args, **kwargs)16701672 if self.viewer and self.viewer.isShowingTasks() and self.viewer.curselection(): 1673 selectedTasks = self.viewer.curselection() 1674 elif self.viewer and self.viewer.isShowingEffort(): 1675 selectedEfforts = self.viewer.curselection() 1676 if selectedEfforts: 1677 selectedTasks = [selectedEfforts[0].task()] 1678 else: 1679 selectedTasks = [self.firstTask(self.viewer.domainObjectsToView())] 1680 else: 1681 selectedTasks = [self.firstTask(self.taskList)] 1682 1683 newEffortCommand = command.NewEffortCommand(self.effortList, selectedTasks) 1684 newEffortCommand.do() 1685 newEffortDialog = dialog.editor.EffortEditor(self.mainWindow(), 1686 newEffortCommand.items, self.settings, self.effortList, 1687 self.mainWindow().taskFile, bitmap=self.bitmap) 1688 if show: 1689 newEffortDialog.Show() 1690 return newEffortDialog1691 1692 @staticmethod1699 1700 -class EffortStart(mixin_uicommand.NeedsSelectedTasksMixin, ViewerCommand, 1701 TaskListCommand):1702 ''' UICommand to start tracking effort for the selected task(s). ''' 170317181705 super(EffortStart, self).__init__(bitmap='clock_icon', 1706 menuText=_('&Start tracking effort\tCtrl-T'), 1707 helpText=help.effortStart, *args, **kwargs)17081710 start = command.StartEffortCommand(self.taskList, 1711 self.viewer.curselection()) 1712 start.do()17131715 return super(EffortStart, self).enabled(event) and \ 1716 any(not task.completed() and not task.isBeingTracked() \ 1717 for task in self.viewer.curselection())1719 1720 -class EffortStartForEffort(mixin_uicommand.NeedsSelectedEffortMixin, 1721 ViewerCommand, TaskListCommand):1722 ''' UICommand to start tracking for the task(s) of selected effort(s). ''' 172317431725 super(EffortStartForEffort, self).__init__(bitmap='clock_icon', 1726 menuText=_('&Start tracking effort'), 1727 helpText=_( 1728 'Start tracking effort for the task(s) of the selected effort(s)'), 1729 *args, **kwargs)1730 1734 17381746 ''' UICommand to start tracking for a specific task. This command can 1747 be used to build a menu with separate menu items for all tasks. 1748 See gui.menu.StartEffortForTaskMenu. ''' 174917641751 self.task = kwargs.pop('task') 1752 subject = self.task.subject() or _('(No subject)') 1753 super(EffortStartForTask, self).__init__( \ 1754 bitmap=self.task.icon(recursive=True), menuText='&' + subject.replace('&', '&&'), 1755 helpText=_('Start tracking effort for %s') % subject, 1756 *args, **kwargs)1757 176117821768 kwargs['taskList'] = base.filter.DeletedFilter(kwargs['taskList']) 1769 super(EffortStartButton, self).__init__(bitmap='clock_menu_icon', 1770 menuText=_('&Start tracking effort'), 1771 helpText=_( 1772 'Select a task via the menu and start tracking effort for it'), 1773 *args, **kwargs)17741776 from taskcoachlib.gui import menu 1777 1778 return menu.StartEffortForTaskMenu(self.mainWindow(), self.taskList)17791785 defaultMenuText = _('Stop tracking or resume tracking effort\tShift+Ctrl+T') 1786 defaultHelpText = help.effortStopOrResume 1787 stopMenuText = _('St&op tracking %s\tShift+Ctrl+T') 1788 stopHelpText = _('Stop tracking effort for the active task(s)') 1789 resumeMenuText = _('&Resume tracking %s\tShift+Ctrl+T') 1790 resumeHelpText = _('Resume tracking effort for the last tracked task') 17911885 1887 if self.anyTrackedEfforts(): 1888 return self.stopHelpText 1889 if paused is None: 1890 paused = self.anyStoppedEfforts() 1891 return self.resumeHelpText if paused else self.defaultHelpText 18921793 super(EffortStop, self).__init__(bitmap='clock_resume_icon', 1794 bitmap2='clock_stop_icon', menuText=self.defaultMenuText, 1795 helpText=self.defaultHelpText, kind=wx.ITEM_CHECK, *args, **kwargs) 1796 self.__tracker = effort.EffortListTracker(self.effortList) 1797 self.__currentBitmap = None # Don't know yet what our bitmap is17981800 selectedEfforts = set() 1801 for item in self.viewer.curselection(): 1802 if isinstance(item, task.Task): 1803 selectedEfforts |= set(item.efforts()) 1804 elif isinstance(item, effort.Effort): 1805 selectedEfforts.add(item) 1806 selectedEfforts &= set(self.__tracker.trackedEfforts()) 1807 return selectedEfforts if selectedEfforts else self.__tracker.trackedEfforts()18081810 efforts = self.efforts() 1811 if efforts: 1812 # Stop the tracked effort(s) 1813 effortCommand = command.StopEffortCommand(self.effortList, efforts) 1814 else: 1815 # Resume tracking the last task 1816 effortCommand = command.StartEffortCommand(self.taskList, 1817 [self.mostRecentTrackedTask()]) 1818 effortCommand.do()18191821 # If there are tracked efforts this command will stop them. If there are 1822 # untracked efforts this command will resume them. Otherwise this 1823 # command is disabled. 1824 return self.anyTrackedEfforts() or self.anyStoppedEfforts()1825 18291831 paused = self.anyStoppedEfforts() and not self.anyTrackedEfforts() 1832 self.updateToolState(not paused) 1833 bitmapName = self.bitmap if paused else self.bitmap2 1834 menuText = self.getMenuText(paused) 1835 if (bitmapName != self.__currentBitmap) or bool( 1836 [item for item in self.menuItems if item.GetItemLabel() != menuText]): 1837 self.__currentBitmap = bitmapName 1838 self.updateToolBitmap(bitmapName) 1839 self.updateToolHelp() 1840 self.updateMenuItems(paused)18411843 if not self.toolbar: 1844 return # Toolbar is hidden 1845 if paused != self.toolbar.GetToolState(self.id): 1846 self.toolbar.ToggleTool(self.id, paused)18471849 if not self.toolbar: 1850 return # Toolbar is hidden 1851 bitmap = wx.ArtProvider_GetBitmap(bitmapName, wx.ART_TOOLBAR, 1852 self.toolbar.GetToolBitmapSize()) 1853 # On wxGTK, changing the bitmap doesn't work when the tool is 1854 # disabled, so we first enable it if necessary: 1855 disable = False 1856 if not self.toolbar.GetToolEnabled(self.id): 1857 self.toolbar.EnableTool(self.id, True) 1858 disable = True 1859 self.toolbar.SetToolNormalBitmap(self.id, bitmap) 1860 if disable: 1861 self.toolbar.EnableTool(self.id, False) 1862 self.toolbar.Realize()18631865 menuText = self.getMenuText(paused) 1866 helpText = self.getHelpText(paused) 1867 for menuItem in self.menuItems: 1868 menuItem.Check(paused) 1869 menuItem.SetItemLabel(menuText) 1870 menuItem.SetHelp(helpText)1871 1873 if self.anyTrackedEfforts(): 1874 trackedEfforts = list(self.efforts()) 1875 subject = _('multiple tasks') if len(trackedEfforts) > 1 \ 1876 else trackedEfforts[0].task().subject() 1877 return self.stopMenuText % self.trimmedSubject(subject) 1878 if paused is None: 1879 paused = self.anyStoppedEfforts() 1880 if paused: 1881 return self.resumeMenuText % \ 1882 self.trimmedSubject(self.mostRecentTrackedTask().subject()) 1883 else: 1884 return self.defaultMenuText1894 return bool(self.effortList.maxDateTime())18951897 return bool(self.efforts())18981900 stopTimes = [(effort.getStop(), effort) for effort in self.effortList if effort.getStop() is not None] 1901 return max(stopTimes)[1].task()1902 1903 @staticmethod1905 trim = len(subject) > maxLength 1906 return subject[:maxLength - len(postFix)] + postFix if trim else subject190719231911 super(CategoryNew, self).__init__(bitmap='new', 1912 menuText=_('New category...\tCtrl-G'), 1913 helpText=help.categoryNew, *args, **kwargs)1914 1916 newCategoryCommand = command.NewCategoryCommand(self.categories) 1917 newCategoryCommand.do() 1918 taskFile = self.mainWindow().taskFile 1919 newCategoryDialog = dialog.editor.CategoryEditor(self.mainWindow(), 1920 newCategoryCommand.items, self.settings, taskFile.categories(), 1921 taskFile, bitmap=self.bitmap) 1922 newCategoryDialog.Show(show)19291927 return command.DragAndDropCategoryCommand(self.categories, dragItems, 1928 drop=[dropItem], part=part)1932 menuText = _('New note...\tCtrl-J') 1933 helpText = help.noteNew 19341951 19541936 super(NoteNew, self).__init__(menuText=self.menuText, 1937 helpText=self.helpText, bitmap='new', *args, **kwargs)1938 1940 if self.viewer and self.viewer.isShowingNotes(): 1941 noteDialog = self.viewer.newItemDialog(bitmap=self.bitmap) 1942 else: 1943 newNoteCommand = command.NewNoteCommand(self.notes, 1944 categories=self.categoriesForTheNewNote()) 1945 newNoteCommand.do() 1946 noteDialog = dialog.editor.NoteEditor(self.mainWindow(), 1947 newNoteCommand.items, self.settings, self.notes, 1948 self.mainWindow().taskFile, bitmap=self.bitmap) 1949 noteDialog.Show(show) 1950 return noteDialog # for testing purposes1957 menuText = _('New ¬e with selected categories...') 1958 helpText = _('Insert a new note with the selected categories checked') 19591962 19681969 1970 -class AttachmentNew(AttachmentsCommand, ViewerCommand, 1971 settings_uicommand.SettingsCommand):19831973 attachments = kwargs['attachments'] 1974 if 'menuText' not in kwargs: 1975 kwargs['menuText'] = attachments.newItemMenuText 1976 kwargs['helpText'] = attachments.newItemHelpText 1977 super(AttachmentNew, self).__init__(bitmap='new', *args, **kwargs)1978 1980 attachmentDialog = self.viewer.newItemDialog(bitmap=self.bitmap) 1981 attachmentDialog.Show(show) 1982 return attachmentDialog # for testing purposes1984 1985 -class AddAttachment(mixin_uicommand.NeedsSelectedAttachmentOwnersMixin, 1986 ViewerCommand, settings_uicommand.SettingsCommand):20041988 super(AddAttachment, self).__init__( \ 1989 menuText=_('&Add attachment...\tShift-Ctrl-A'), 1990 helpText=help.addAttachment, bitmap='paperclip_icon', 1991 *args, **kwargs)19921994 filename = widgets.AttachmentSelector() 1995 if not filename: 1996 return 1997 attachmentBase = self.settings.get('file', 'attachmentbase') 1998 if attachmentBase: 1999 filename = attachment.getRelativePath(filename, attachmentBase) 2000 addAttachmentCommand = command.AddAttachmentCommand( \ 2001 self.viewer.presentation(), self.viewer.curselection(), 2002 attachments=[attachment.FileAttachment(filename)]) 2003 addAttachmentCommand.do()2007 attachmentBase = settings.get('file', 'attachmentbase') 2008 for eachAttachment in attachments: 2009 try: 2010 eachAttachment.open(attachmentBase) 2011 except Exception, instance: # pylint: disable=W0703 2012 showerror(render.exception(Exception, instance), 2013 caption=_('Error opening attachment'), 2014 style=wx.ICON_ERROR)20152016 2017 -class AttachmentOpen(mixin_uicommand.NeedsSelectedAttachmentsMixin, 2018 ViewerCommand, AttachmentsCommand, 2019 settings_uicommand.SettingsCommand):20282021 attachments = kwargs['attachments'] 2022 super(AttachmentOpen, self).__init__(bitmap='fileopen', 2023 menuText=attachments.openItemMenuText, 2024 helpText=attachments.openItemHelpText, *args, **kwargs)2025 2027 openAttachments(self.viewer.curselection(), self.settings, showerror)2029 2030 -class OpenAllAttachments(mixin_uicommand.NeedsSelectionWithAttachmentsMixin, 2031 ViewerCommand, settings_uicommand.SettingsCommand):20432033 super(OpenAllAttachments, self).__init__( \ 2034 menuText=_('&Open all attachments...\tShift+Ctrl+O'), 2035 helpText=help.openAllAttachments, bitmap='paperclip_icon', 2036 *args, **kwargs)2037 2039 allAttachments = [] 2040 for item in self.viewer.curselection(): 2041 allAttachments.extend(item.attachments()) 2042 openAttachments(allAttachments, self.settings, showerror)20702047 self._dialogTitle = kwargs.pop('dialogTitle') 2048 self._dialogText = kwargs.pop('dialogText') 2049 self._direction = kwargs.pop('direction', None) 2050 self.closed = True 2051 super(DialogCommand, self).__init__(*args, **kwargs)20522054 self.closed = False 2055 # pylint: disable=W0201 2056 self.dialog = widgets.HTMLDialog(self._dialogTitle, self._dialogText, 2057 bitmap=self.bitmap, 2058 direction=self._direction) 2059 for event in wx.EVT_CLOSE, wx.EVT_BUTTON: 2060 self.dialog.Bind(event, self.onClose) 2061 self.dialog.Show()2062 206720832074 if operating_system.isMac(): 2075 # Use default keyboard shortcut for Mac OS X: 2076 menuText = _('&Help contents\tCtrl+?') 2077 else: 2078 # Use a letter, because 'Ctrl-?' doesn't work on Windows: 2079 menuText = _('&Help contents\tCtrl+H') 2080 super(Help, self).__init__(menuText=menuText, helpText=help.help, 2081 bitmap='led_blue_questionmark_icon', dialogTitle=_('Help'), 2082 dialogText=help.helpHTML, id=wx.ID_HELP, *args, **kwargs)20932087 super(Tips, self).__init__(menuText=_('&Tips'), 2088 helpText=_('Tips about the program'), 2089 bitmap='lamp_icon', *args, **kwargs)20902108 2117 21262097 super(Anonymize, self).__init__(menuText=_('Anonymize'), 2098 helpText=_('Anonymize a task file to attach it to a bug report'), 2099 *args, **kwargs)21002102 anonymized_filename = anonymize(self.iocontroller.filename()) 2103 wx.MessageBox(_('Your task file has been anonymized and saved to:') \ 2104 + '\n' + anonymized_filename, _('Finished'), wx.OK)21052137 2151 2159 2166 2175 2183 2192 21992130 super(CheckForUpdate, self).__init__(menuText=_('Check for update'), 2131 helpText=_( 2132 'Check for the availability of a new version of %s') % meta.name, 2133 bitmap='box_icon', *args, **kwargs)213422092203 super(MainWindowRestore, self).__init__(menuText=_('&Restore'), 2204 helpText=_('Restore the window to its previous state'), 2205 bitmap='restore', *args, **kwargs)22062212 # Search can only be attached to a real viewer, not to a viewercontainer22792214 self.__bound = False 2215 super(Search, self).__init__(*args, helpText=_('Search'), **kwargs) 2216 assert self.viewer.isSearchable()22172218 - def onFind(self, searchString, matchCase, includeSubItems, 2219 searchDescription, regularExpression):2220 if self.__bound: 2221 self.viewer.setSearchFilter(searchString, matchCase, includeSubItems, 2222 searchDescription, regularExpression)22232225 self.__bound = True 2226 searchString, matchCase, includeSubItems, searchDescription, regularExpression = \ 2227 self.viewer.getSearchFilter() 2228 #pylint: disable=W0201 2229 self.searchControl = widgets.SearchCtrl(toolbar, value=searchString, 2230 style=wx.TE_PROCESS_ENTER, matchCase=matchCase, 2231 includeSubItems=includeSubItems, 2232 searchDescription=searchDescription, 2233 regularExpression=regularExpression, 2234 callback=self.onFind) 2235 toolbar.AddControl(self.searchControl) 2236 self.bindKeyDownInViewer() 2237 self.bindKeyDownInSearchCtrl()22382240 ''' Bind wx.EVT_KEY_DOWN to self.onViewerKeyDown so we can catch 2241 Ctrl-F. ''' 2242 widget = self.viewer.getWidget() 2243 try: 2244 window = widget.GetMainWindow() 2245 except AttributeError: 2246 window = widget 2247 window.Bind(wx.EVT_KEY_DOWN, self.onViewerKeyDown)22482250 ''' Bind wx.EVT_KEY_DOWN to self.onSearchCtrlKeyDown so we can catch 2251 the Escape key and drop down the menu on Ctrl-Down. ''' 2252 self.searchControl.getTextCtrl().Bind(wx.EVT_KEY_DOWN, 2253 self.onSearchCtrlKeyDown)2254 22582260 ''' On Ctrl-F, move focus to the search control. ''' 2261 if event.KeyCode == ord('F') and event.CmdDown() and \ 2262 not event.AltDown(): 2263 self.searchControl.SetFocus() 2264 else: 2265 event.Skip()22662268 ''' On Escape, move focus to the viewer, on Ctrl-Down popup the 2269 menu. ''' 2270 if event.KeyCode == wx.WXK_ESCAPE: 2271 self.viewer.SetFocus() 2272 elif event.KeyCode == wx.WXK_DOWN and event.AltDown(): 2273 self.searchControl.PopupMenu() 2274 else: 2275 event.Skip()22762282 # Search can only be attached to a real viewer, not to a viewercontainer23462284 self.__bound = False 2285 super(QuickAdd, self).__init__(*args, helpText=_('QuickAdd'), **kwargs)22862288 self.__bound = True 2289 self.QuickAddControl = wx.TextCtrl(toolbar, -1, "", style=wx.TE_PROCESS_ENTER) 2290 toolbar.AddControl(self.QuickAddControl) 2291 self.bindKeyDownEnter() 2292 self.bindKeyDownInSearchCtrl()22932295 ''' Bind wx.EVT_KEY_DOWN to self.onSearchCtrlKeyDown so we can catch 2296 the Escape key''' 2297 self.QuickAddControl.Bind(wx.EVT_KEY_DOWN, self.onSearchCtrlKeyDown)22982300 ''' Bind wx.EVT_KEY_DOWN to self.onViewerKeyDown so we can catch 2301 Ctrl-F. ''' 2302 self.QuickAddControl.Bind(wx.EVT_KEY_DOWN, self.onEnterKey)2303 23072309 ''' On Escape, move focus to the viewer''' 2310 if event.KeyCode == wx.WXK_ESCAPE: 2311 self.viewer.SetFocus() 2312 else: 2313 event.Skip()23142316 if event.KeyCode == wx.WXK_RETURN: 2317 taskArgs = command.Parser().getAnswers(self.QuickAddControl.GetValue()) 2318 categories = [] 2319 2320 for categoryName in taskArgs['Categories']: 2321 category = self.mainWindow().taskFile.categories().findCategoryByName(categoryName) 2322 if category is None: 2323 newCategoryCommand = command.NewCategoryCommand(self.mainWindow().taskFile.categories(), 2324 subject=categoryName) 2325 newCategoryCommand.do() 2326 categories.append(self.mainWindow().taskFile.categories().findCategoryByName(categoryName)) 2327 else: 2328 categories.append(self.mainWindow().taskFile.categories().findCategoryByName(categoryName)) 2329 2330 newTaskCommand = command.NewTaskCommand(self.mainWindow().taskFile.tasks(), 2331 subject=taskArgs['Title'], description=taskArgs['Description'], 2332 plannedStartDateTime=taskArgs['StartDate'], 2333 dueDateTime=taskArgs['EndDate'], 2334 priority=taskArgs['Priority'], 2335 actualStartDateTime=taskArgs['ActualStartDate'], 2336 completionDateTime=taskArgs['CompletionDate'], 2337 categories=categories) 2338 newTaskCommand.do() 2339 print self.settings.get('file', 'recentfiles') 2340 self.QuickAddControl.Clear() 2341 else: 2342 event.Skip()2343235223912354 ''' Add our choice control to the toolbar. ''' 2355 # pylint: disable=W0201 2356 self.choiceCtrl = wx.Choice(toolbar, choices=self.choiceLabels) 2357 self.currentChoice = self.choiceCtrl.Selection 2358 self.choiceCtrl.Bind(wx.EVT_CHOICE, self.onChoice) 2359 toolbar.AddControl(self.choiceCtrl)23602362 if self.choiceCtrl is not None: 2363 self.choiceCtrl.Unbind(wx.EVT_CHOICE) 2364 self.choiceCtrl = None 2365 super(ToolbarChoiceCommandMixin, self).unbind(window, id_)23662368 ''' The user selected a choice from the choice control. ''' 2369 choiceIndex = event.GetInt() 2370 if choiceIndex == self.currentChoice: 2371 return 2372 self.currentChoice = choiceIndex 2373 self.doChoice(self.choiceData[choiceIndex])2374 2377 23802382 ''' Programmatically set the current choice in the choice control. ''' 2383 if self.choiceCtrl is not None: 2384 index = self.choiceData.index(choice) 2385 self.choiceCtrl.Selection = index 2386 self.currentChoice = index23872392 2393 -class EffortViewerAggregationChoice(ToolbarChoiceCommandMixin, 2394 settings_uicommand.SettingsCommand, 2395 ViewerCommand):2396 choiceLabels = [_('Effort details'), _('Effort per day'), 2397 _('Effort per week'), _('Effort per month')] 2398 choiceData = ['details', 'day', 'week', 'month'] 239924182401 super(EffortViewerAggregationChoice, self).__init__(helpText=_('Aggregation mode'), 2402 **kwargs)24032405 super(EffortViewerAggregationChoice, self).appendToToolBar(*args, 2406 **kwargs) 2407 self.setChoice(self.settings.gettext(self.viewer.settingsSection(), 2408 'aggregation')) 2409 pub.subscribe(self.on_setting_changed, 2410 'settings.%s.aggregation' % self.viewer.settingsSection())2411 24152419 2420 -class EffortViewerAggregationOption(settings_uicommand.UIRadioCommand, 2421 ViewerCommand):24292430 2431 -class TaskViewerTreeOrListChoice(ToolbarChoiceCommandMixin, 2432 settings_uicommand.UICheckCommand, 2433 ViewerCommand):2434 choiceLabels = [_('Tree'), _('List')] 2435 choiceData = [True, False] 24362456 24672438 super(TaskViewerTreeOrListChoice, self).__init__( \ 2439 menuText=self.choiceLabels[0], 2440 helpText=_('When checked, show tasks as tree, ' 2441 'otherwise show tasks as list'), *args, **kwargs)24422444 super(TaskViewerTreeOrListChoice, self).appendToToolBar(*args, **kwargs) 2445 self.setChoice(self.settings.getboolean(self.viewer.settingsSection(), 2446 'treemode')) 2447 pub.subscribe(self.on_setting_changed, 2448 'settings.%s.treemode' % self.viewer.settingsSection())2449 24532468 2469 -class CategoryViewerFilterChoice(ToolbarChoiceCommandMixin, 2470 settings_uicommand.UICheckCommand):2471 choiceLabels = [_('Filter on all checked categories'), 2472 _('Filter on any checked category')] 2473 choiceData = [True, False] 247424982476 super(CategoryViewerFilterChoice, self).__init__( \ 2477 menuText=self.choiceLabels[0], 2478 helpText=_('When checked, filter on all checked categories, ' 2479 'otherwise on any checked category'), *args, **kwargs)24802482 super(CategoryViewerFilterChoice, self).appendToToolBar(*args, **kwargs) 2483 pub.subscribe(self.on_setting_changed, 2484 'settings.view.categoryfiltermatchall')2485 2488 24912493 self.settings.setboolean('view', 'categoryfiltermatchall', 2494 self._isMenuItemChecked(event))24952499 2500 -class SquareTaskViewerOrderChoice(ToolbarChoiceCommandMixin, 2501 settings_uicommand.SettingsCommand, 2502 ViewerCommand):2503 choiceLabels = [_('Budget'), _('Time spent'), _('Fixed fee'), _('Revenue'), 2504 _('Priority')] 2505 choiceData = ['budget', 'timeSpent', 'fixedFee', 'revenue', 'priority'] 2506 250925212511 super(SquareTaskViewerOrderChoice, self).appendToToolBar(*args, 2512 **kwargs) 2513 pub.subscribe(self.on_setting_changed, 2514 'settings.%s.sortby' % self.viewer.settingsSection())2515 25182522 2523 -class SquareTaskViewerOrderByOption(settings_uicommand.UIRadioCommand, 2524 ViewerCommand):25322535 menuText = _('&Configure') 2536 helpText = _('Configure the calendar viewer') 2537 bitmap = 'wrench_icon' 25382546 25602540 super(CalendarViewerConfigure, self).__init__( \ 2541 menuText=self.menuText, helpText=self.helpText, bitmap=self.bitmap, 2542 *args, **kwargs)25432563 menuText = _('&Next period') 2564 helpText = _('Show next period') 2565 bitmap = 'next' 2566 calendarViewType = wxSCHEDULER_NEXT25672570 menuText = _('&Previous period') 2571 helpText = _('Show previous period') 2572 bitmap = 'prev' 2573 calendarViewType = wxSCHEDULER_PREV25742577 menuText = _('&Today') 2578 helpText = _('Show today') 2579 bitmap = 'calendar_icon' 2580 calendarViewType = wxSCHEDULER_TODAY258126042586 super(ToggleAutoColumnResizing, self).__init__( \ 2587 menuText=_('&Automatic column resizing'), 2588 helpText=_('When checked, automatically resize columns to fill' 2589 ' available space'), 2590 *args, **kwargs) 2591 wx.CallAfter(self.updateWidget)2592 2595 25992601 self.settings.set(self.viewer.settingsSection(), 'columnautoresizing', 2602 str(self._isMenuItemChecked(event))) 2603 self.updateWidget()26422608 self.sliderCtrl = None 2609 super(ViewerPieChartAngle, self).__init__( \ 2610 helpText=_('Set pie chart angle'), *args, **kwargs)26112613 ''' Add our slider control to the toolbar. ''' 2614 # pylint: disable=W0201 2615 self.sliderCtrl = wx.Slider(toolbar, minValue=0, maxValue=90, 2616 value=self.getCurrentAngle(), size=(120, -1)) 2617 self.sliderCtrl.Bind(wx.EVT_SLIDER, self.onSlider) 2618 toolbar.AddControl(self.sliderCtrl)26192621 if self.sliderCtrl is not None: 2622 self.sliderCtrl.Unbind(wx.EVT_SLIDER) 2623 self.sliderCtrl = None 2624 super(ViewerPieChartAngle, self).unbind(window, itemId)2625 2630 2633 26372639 if self.sliderCtrl is not None: 2640 self.settings.setint(self.viewer.settingsSection(), 'piechartangle', 2641 self.sliderCtrl.GetValue())2643 2644 -class RoundingPrecision(ToolbarChoiceCommandMixin, ViewerCommand, 2645 settings_uicommand.SettingsCommand):2646 roundingChoices = (0, 1, 3, 5, 6, 10, 15, 20, 30, 60) # Minutes 2647 choiceData = [minutes * 60 for minutes in roundingChoices] # Seconds 2648 choiceLabels = [_('No rounding'), _('1 minute')] + \ 2649 [_('%d minutes') % minutes for minutes in roundingChoices[2:]] 2650 26532656 266527092669 self.checkboxCtrl = None 2670 super(AlwaysRoundUp, self).__init__( \ 2671 menuText=_('&Always round up'), 2672 helpText=_('Always round up to the next rounding increment'), 2673 *args, **kwargs)26742676 ''' Add a checkbox control to the toolbar. ''' 2677 # pylint: disable=W0201 2678 self.checkboxCtrl = wx.CheckBox(toolbar, label=self.menuText) 2679 self.checkboxCtrl.Bind(wx.EVT_CHECKBOX, self.onCheck) 2680 toolbar.AddControl(self.checkboxCtrl)26812683 if self.checkboxCtrl is not None: 2684 self.checkboxCtrl.Unbind(wx.EVT_CHECKBOX) 2685 self.checkboxCtrl = None 2686 super(AlwaysRoundUp, self).unbind(window, itemId)2687 2691 2694 2697 2701 2705
| Trees | Indices | Help |
|---|
| Generated by Epydoc 3.0.1 on Mon Nov 25 04:14:25 2013 | http://epydoc.sourceforge.net |